
#ifndef __ui_gfx_color_analysis_h__
#define __ui_gfx_color_analysis_h__

#pragma once

#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"

#include "SkColor.h"

namespace gfx
{

    // This class exposes the sampling method to the caller, which allows
    // stubbing out for things like unit tests. Might be useful to pass more
    // arguments into the GetSample method in the future (such as which
    // cluster is being worked on, etc.).
    class KMeanImageSampler
    {
    public:
        virtual int GetSample(int width, int height) = 0;

    protected:
        KMeanImageSampler();
        virtual ~KMeanImageSampler();
    };

    // This sampler will pick a random pixel as a sample centroid.
    class RandomSampler : public KMeanImageSampler
    {
    public:
        RandomSampler();
        virtual ~RandomSampler();

        virtual int GetSample(int width, int height);
    };

    // This sampler will pick pixels from an evenly spaced grid.
    class GridSampler : public KMeanImageSampler
    {
    public:
        GridSampler();
        virtual ~GridSampler();

        virtual int GetSample(int width, int height);

    private:
        // The number of times GetSample has been called.
        int calls_;
    };

    // Returns a recommended background color for a PNG image. This color might
    // not even exist in the image, but it is typically representative of the
    // image and tinted towards the white end of the spectrum.
    // The function CalculateKMeanColorOfPNG is used to grab the KMean calculated
    // color of the image, then the color is moved to HSV space so the saturation
    // and luminance can be modified to move the color towards the white end of
    // the spectrum. The color is then moved back to RGB space and returned.
    SkColor CalculateRecommendedBgColorForPNG(scoped_refptr<RefCountedMemory> png);

    SkColor CalculateRecommendedBgColorForPNG(scoped_refptr<RefCountedMemory> png,
        KMeanImageSampler& sampler);

    // Returns an SkColor that represents the calculated dominant color in the png.
    // This uses a KMean clustering algorithm to find clusters of pixel colors in
    // RGB space.
    // |png| represents the data of a png encoded image.
    // |darkness_limit| represents the minimum sum of the RGB components that is
    // acceptable as a color choice. This can be from 0 to 765.
    // |brightness_limit| represents the maximum sum of the RGB components that is
    // acceptable as a color choice. This can be from 0 to 765.
    //
    // RGB KMean Algorithm (N clusters, M iterations):
    // TODO (dtrainor): Try moving most/some of this to HSV space?  Better for
    // color comparisons/averages?
    // 1.Pick N starting colors by randomly sampling the pixels. If you see a
    //   color you already saw keep sampling. After a certain number of tries
    //   just remove the cluster and continue with N = N-1 clusters (for an image
    //   with just one color this should devolve to N=1). These colors are the
    //   centers of your N clusters.
    //   TODO (dtrainor): Check to ignore colors with an alpha of 0?
    // 2.For each pixel in the image find the cluster that it is closest to in RGB
    //   space. Add that pixel's color to that cluster (we keep a sum and a count
    //   of all of the pixels added to the space, so just add it to the sum and
    //   increment count).
    // 3.Calculate the new cluster centroids by getting the average color of all of
    //   the pixels in each cluster (dividing the sum by the count).
    // 4.See if the new centroids are the same as the old centroids.
    //     a) If this is the case for all N clusters than we have converged and
    //        can move on.
    //     b) If any centroid moved, repeat step 2 with the new centroids for up
    //        to M iterations.
    // 5.Once the clusters have converged or M iterations have been tried, sort
    //   the clusters by weight (where weight is the number of pixels that make up
    //   this cluster).
    // 6.Going through the sorted list of clusters, pick the first cluster with the
    //   largest weight that's centroid fulfills the equation
    //   |darkness_limit| < SUM(R, G, B) < |brightness_limit|. Return that color.
    //   If no color fulfills that requirement return the color with the largest
    //   weight regardless of whether or not it fulfills the equation above.
    SkColor CalculateKMeanColorOfPNG(scoped_refptr<RefCountedMemory> png,
        uint32_t darkness_limit,
        uint32_t brightness_limit);

    SkColor CalculateKMeanColorOfPNG(scoped_refptr<RefCountedMemory> png,
        uint32_t darkness_limit,
        uint32_t brightness_limit,
        KMeanImageSampler& sampler);

} //namespace gfx

#endif //__ui_gfx_color_analysis_h__